FSM
이론적으로는 무어 방식과 밀리 방식이 있다. 무어는 상태에 따른 출력만 존재하고, 밀리는 상태 + 현재 입력까지 주어진다. 실제 사용하는 FSM은 밀리 상태에 가까운데, 입력이 없이도 가능한 노드가 있는 등 무어 머신의 특성도 가지고 있다.
가장 간단한 구현
가장 쉬운 구현은
IF 혹은 Switch-Case 를 기반으로 State를 변수로 지정하여 구현할 수 있다.간단한 구현 코드(C)
enum STATE { START, WAITING, PROCESSING, ERROR, FINISH }; static enum STATE state = START; // 상태 실시 void handle_state() { switch(state) { case START: action_start() // ... } } // 상태 전이 동작 void next_state() { switch(state) { case START: state = WAITING; break; case WAITING: state = PROCESSING; break; // ... } }
→ 만약 State가 수백 개라면? 가능한 출력이 수십개라면?
엄청나게 많은 분기 코드 발생.
상태 패턴
상태패턴은 위 refactoring.guru에 설명이 자세하게 되어있으니 참조
- 멤버로 state 변수를 가지고 있는 Context라는 클래스가 핵심
- State를 상속 중인 여러개의 State 클래스가 존재
- 현재 Context 안에 있는 State 객체가 다음 State를 결정해서 자기 자신을 교체
상태 객체가 스스로 다른 상태로 교체하기 때문에 수많은 switch-case 문이 필요 없다.
그러나 Embedded System 등 속도가 중요한 시스템에서, 상태 수가 적은 FSM을 다룰 때는 상태 패턴을 써야 함
HFSM
각 FSM을 모듈화 한 다음에, 이 모듈을 노드로 하는 계층적 FSM을 구성, 상위 단계로 보기 때문에 좀 더 상위 문맥을 파악하기도 쉽다.
BT(Behavior Tree)
BT는 Stack 기반으로 동작한다.
BehaviorTree.cpp
robotics 분야에서 흔히 쓰이는 Behavior Tree 구현체
왜 BT가 필요한가?
- 모듈화
- 컴포넌트 재사용성
- Composability
- 관심사의 분리